package com.zhijiaoyun.log;

import com.zhijiaoyun.common.CommonUtils;
import com.zhijiaoyun.common.DateUtils;
import com.zhijiaoyun.model.Log;
import com.zhijiaoyun.service.ILogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author shisfish
 * @date 2017/6/6
 */
@Aspect
@Component
public class SystemLogAop {

    @Resource
    ILogService logService;

    @Resource
    HttpServletRequest request;

    @Pointcut("@annotation(com.zhijiaoyun.log.SystemLog)")
    public void log() {
    }

    @Pointcut("execution(* com.zhijiaoyun.controller.LoginController.login(..))")
    public void login() {
        
    }

    @SuppressWarnings("rawtypes")
    @After("login()")
    public void beforeExec(JoinPoint pjp) throws Throwable {

        StringBuffer sb = new StringBuffer();
        sb.append(DateUtils.getDateFormat(new Date(), null));
        sb.append(" ");

        //常见日志实体对象
        Log log = new Log();
        //获取登录账户
        String account = String.valueOf(request.getParameter("account"));
        log.setUsername(account);
        //获取ip
        String ip = CommonUtils.getIp(request);
        log.setRequestIp(ip);
        sb.append(ip);
        sb.append(" \n");
        sb.append(account);
        sb.append("执行操作   ");
        // 拦截的实体类，就是当前正在执行的controller
        Object target = pjp.getTarget();
        // 拦截的方法名称。当前正在执行的方法
        String methodName = pjp.getSignature().getName();
        // 拦截的方法参数类型
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Class[] parameterTypes = msig.getMethod().getParameterTypes();

        // 获得被拦截的方法
        Method method = null;
        try {
            method = target.getClass().getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e1) {
            e1.printStackTrace();
        } catch (SecurityException e1) {
            e1.printStackTrace();
        }
        if (null != method) {
            // 判断是否包含自定义的注解，SystemLog就是自定义的注解，登录没有注解
            if (!method.isAnnotationPresent(SystemLog.class)) {
                log.setMethod("login");
                log.setDescription("管理员登录");

                sb.append("login");
                sb.append("(");
                sb.append("管理员登录");
                sb.append(") ");
                try {
                    log.setExceptionDetail("执行成功");
                    sb.append("执行成功");
                    //保存进数据库
                    sb.append("\n\n");
                    logService.insertLog(log);
                    saveLog(sb);
                } catch (Throwable e) {
                    log.setExceptionDetail("执行失败");
                    sb.append("执行失败");
                    sb.append("\n\n");
                    logService.insertLog(log);
                    saveLog(sb);
                }
            }
        }
    }

    private void saveLog(StringBuffer sb) throws IOException {
//		String filePath = "D:/log";
//		CommonUtils.checkPath(filePath);
//		filePath += "/" + CommonUtils.getDateFormat(new Date(), "yyy-MM-dd") + ".log";
//		CommonUtils.createFile(filePath);
//		FileWriter  fw = new FileWriter(filePath, true);
//		fw.write(sb.toString());
//		fw.flush();
//		fw.close();
    }

    @SuppressWarnings({"rawtypes"})
    @Around("log()")
    public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable {
        StringBuffer sb = new StringBuffer();
        sb.append(DateUtils.getDateFormat(new Date(), null));
        sb.append(" ");

        //日志实体对象
        Log log = new Log();
        //获取登录用户账户
        String username = String.valueOf(request.getAttribute("createUser"));
        log.setUsername(username);

        //获取ip
        String ip = CommonUtils.getIp(request);
        log.setRequestIp(ip);

        sb.append(ip);
        sb.append(" \n");
        sb.append(username);
        sb.append("执行操作   ");

        // 拦截的实体类，就是当前正在执行的controller
        Object target = pjp.getTarget();
        // 拦截的方法名称。当前正在执行的方法
        String methodName = pjp.getSignature().getName();
        // 拦截的方法参数类型
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Class[] parameterTypes = msig.getMethod().getParameterTypes();

        Object object = null;
        // 获得被拦截的方法
        Method method = null;
        try {
            method = target.getClass().getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e1) {
            e1.printStackTrace();
        } catch (SecurityException e1) {
            e1.printStackTrace();
        }
        if (null != method) {
            // 判断是否包含自定义的注解，SystemLog就是自定义的注解
            if (method.isAnnotationPresent(SystemLog.class)) {
                SystemLog systemlog = method.getAnnotation(SystemLog.class);
                log.setMethod(systemlog.function());
                log.setDescription(systemlog.description());

                sb.append(systemlog.description());
                sb.append("(");
                sb.append(systemlog.function());
                sb.append(") ");

                try {
                    object = pjp.proceed();
                    if (object instanceof Map || object instanceof HashMap || object instanceof AbstractMap) {
                        AbstractMap map = (AbstractMap) object;
                        if ((Integer) map.get("code") == 0) {
                            log.setExceptionDetail("执行成功");
                            log.setExceptionCode("0");
                            sb.append("执行成功");
                        } else {
                            log.setExceptionDetail("执行失败：" + String.valueOf(map.get("message")));
                            log.setExceptionCode(String.valueOf(map.get("code")));
                            sb.append(String.valueOf(map.get("message")));
                        }
                    } else {
                        log.setExceptionDetail("执行失败");
                        log.setExceptionCode("0");
                        sb.append("执行失败");
                    }
                    //保存进数据库
                    sb.append("\n\n");
                    logService.insertLog(log);
                    saveLog(sb);
                } catch (Throwable e) {
                    log.setExceptionDetail("执行失败");
                    sb.append("执行失败");
                    sb.append("\n\n");
                    logService.insertLog(log);
                    saveLog(sb);
                }
            } else {//没有包含注解
                object = pjp.proceed();
            }
        } else { //不需要拦截直接执行
            object = pjp.proceed();
        }
        return object;
    }

}
